package com.beautify.qrcode.utils;

import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.util.*;
import java.util.List;

import com.beautify.qrcode.constants.PointEnum;
import lombok.extern.slf4j.Slf4j;
import net.coobird.thumbnailator.Thumbnails;
import net.coobird.thumbnailator.geometry.Coordinate;
import net.coobird.thumbnailator.geometry.Positions;

import com.beautify.qrcode.constants.StructEnum;
import com.beautify.qrcode.model.WatermarkVo;
import com.beautify.qrcode.struct.ITemplateType;
import com.beautify.qrcode.struct.TemplateTypeService;

/**
 * 黑白二维码打模板图元水印
 *
 * @author keia
 * @since 2022/1/13 20:21
 */
@Slf4j
public class WatermarkUtil {

    private Thumbnails.Builder builder;
    private WatermarkVo watermarkVo;
    private Map<StructEnum, List> structEnumMap;
    private Vector pointList = new Vector();
    private ITemplateType iTemplateType;

    private WatermarkUtil(){
        structEnumMap = new HashMap<>();
    }

    /**
     * 步骤1
     * @return
     */
    public static WatermarkUtil create(){
        return new WatermarkUtil();
    }

    public WatermarkUtil watermarkVo(WatermarkVo watermarkVo) throws Exception{
        this.watermarkVo = watermarkVo;
        this.iTemplateType = new TemplateTypeService().getTemplate(watermarkVo.getTemplateType());
        for (StructEnum structEnum: iTemplateType.getTemplateStructList()) {
            structEnumMap.put(structEnum,new ArrayList());
        }
        return this;
    }

    /**
     * 步骤2
     * @return
     */
    public WatermarkUtil createCanvas() throws IOException {
        builder = Thumbnails.of(new ImageLoadUtil().createBackGroundImage());
        builder.size(watermarkVo.getHeight(), watermarkVo.getHeight());
        return this;
    }

    /**
     * 步骤3
     * @return
     */
    public WatermarkUtil createEye() throws Exception {
        BufferedImage outputEye = new ImageLoadUtil().getTemplateImage(watermarkVo.getTemplateType(), StructEnum.Eye,watermarkVo.getCellBit());
        builder
            .watermark(Positions.TOP_LEFT, outputEye, 1f)
            .watermark(Positions.TOP_RIGHT,outputEye,1f)
            .watermark(Positions.BOTTOM_LEFT,outputEye,1f);

        boolean[][] s = watermarkVo.getCellArray();
        //去除3个眼镜
        for (int x = 0; x < s.length; x++) {
            for (int y = 0; y < s.length; y++) {
                //第一个眼镜
                if(x<=7 && y<=7){
                    s[x][y] = false;
                }
                //第二个眼镜
                if(x>= s.length-7 && y<=7){
                    s[x][y] = false;
                }

                //第三个眼镜
                if(x<=7 && y>=s.length-7){
                    s[x][y] = false;
                }
            }
        }
        watermarkVo.setCellArray(s);
        return this;
    }

    public WatermarkUtil createNByN() throws Exception{
        boolean[][] s = watermarkVo.getCellArray();
        for (int x = 0; x < s.length; x++) {
            for (int y = 0; y < s.length; y++) {
                if(s[x][y]){
                    pointList.add(new Point(x,y));
                }
            }
        }

        for (StructEnum struct: iTemplateType.getTemplateStructList()) {
            fillAnyType(struct);
        }

        for (StructEnum struct: iTemplateType.getTemplateStructList()) {
            List<Point> points = structEnumMap.get(struct);
            for (Point p: points ) {
                int xPoint = p.x * watermarkVo.getCellBit();
                int yPoint = p.y * watermarkVo.getCellBit();
                BufferedImage output = new ImageLoadUtil().getTemplateImage(watermarkVo.getTemplateType(), struct,watermarkVo.getCellBit());
                Coordinate cell1Position = new Coordinate(xPoint,yPoint);
                builder.watermark(cell1Position,output,1f);
            }
        }
        return this;
    }

    public void fillAnyType(StructEnum struct){
        ListIterator<Point> it = pointList.listIterator();
        int index=0;
        //循环要黑色格list
        while(it.hasNext()){
            Point point = it.next();
            if(test(point,struct)==true){
                fillType(point,struct);
                structEnumMap.get(struct).add(point);
                it=pointList.listIterator(index);
            }else {
                index++;
            }
        }
    }

    public void fillType(Point point, StructEnum struct) {
        boolean[][] s  = watermarkVo.getCellArray();
        for(int x = 0;x <(int)struct.getPoint().x;x++) {
            for(int y=0;y<(int)struct.getPoint().y;y++) {
                s[x+point.x][y+point.y] = false;
                pointList.remove(new Point(x+point.x,y+point.y));
            }
        }
        watermarkVo.setCellArray(s);
    }

    public boolean test(Point point, StructEnum struct) {
        StringBuilder temp= new StringBuilder();
        boolean[][] s  = watermarkVo.getCellArray();
        for(int x = 0;x <(int)struct.getPoint().x;x++) {
            for(int y=0;y<(int)struct.getPoint().y;y++) {
                if(x+point.x<s.length&& y+point.y<s.length){
                    if(s[x+point.x][y+point.y]){
                        temp.append(PointEnum.POINT_1.getType());
                    }else{
                        temp.append(PointEnum.POINT_0.getType());
                    }
                }
            }
            temp.append(PointEnum.POINT_0.getType());
        }
        if(temp.toString().equals(struct.getStr())) {
            return true;
        } else{
            return false;
        }
    }

    /**
     * 步骤last
     * @return
     */
    public WatermarkUtil createOneByOne() throws Exception {
        boolean[][] s = watermarkVo.getCellArray();
        for (int x = 0; x < s.length; x++) {
            for (int y = 0; y < s.length; y++) {
                if(s[x][y]){
                    int xPoint = x * watermarkVo.getCellBit();
                    int yPoint = y * watermarkVo.getCellBit();
                    BufferedImage output = new ImageLoadUtil()
                        .getTemplateImage(watermarkVo.getTemplateType(), StructEnum.OneByOne,watermarkVo.getCellBit());
                    Coordinate cell1Position = new Coordinate(xPoint,yPoint);
                    builder.watermark(cell1Position,output,1f);
                }
            }
        }
        return this;
    }

    /**
     * 输出图片对象
     * @return
     * @throws IOException
     */
    public BufferedImage outputImage() throws IOException {
        return builder.outputQuality(1f).asBufferedImage();
    }

}
